////////////////////////////////////////////////////////////////////////////////
// OpenGLView.cpp : implementation of the COpenGLView class
//
#include "stdafx.h"
#include "OpenGL.h"

#include "OpenGLDoc.h"
#include "OpenGLView.h"
#include "ObjectStorage.h"

//#include <iostream>
//using std::cout;
//using std::endl;

#include "MaterialDlg.h"
#include "LightDialog.h"
#include "ColorSettingsDialog.h"
#include "MouseSettingsDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "PngWrapper.h"
#include "iritSkel.h"


// For Status Bar access
#include "MainFrm.h"

#include "OpenGLMacros.h"
#include <sstream>
#include <map>
using std::stringstream;


// Use this macro to display text messages in the status bar.
#define STATUS_BAR_TEXT( str ) ( ( (CMainFrame*)GetParentFrame( ) )->getStatusBar( ).SetWindowText( str ) )


/////////////////////////////////////////////////////////////////////////////
// COpenGLView

IMPLEMENT_DYNCREATE( COpenGLView, CView )

BEGIN_MESSAGE_MAP( COpenGLView, CView )
	//{{AFX_MSG_MAP( COpenGLView )
	ON_WM_ERASEBKGND( )
	ON_WM_CREATE( )
	ON_WM_DESTROY( )
	ON_WM_SIZE( )
	ON_COMMAND( ID_FILE_LOAD, OnFileLoad )
	ON_COMMAND( ID_VIEW_ORTHOGRAPHIC_VIEW, OnViewOrthographicView )
	ON_UPDATE_COMMAND_UI( ID_VIEW_ORTHOGRAPHIC_VIEW, OnUpdateViewOrthographicView )
	ON_COMMAND( ID_VIEW_PERSPECTIVE_VIEW, OnViewPerspectiveView )
	ON_UPDATE_COMMAND_UI( ID_VIEW_PERSPECTIVE_VIEW, OnUpdateViewPerspectiveView )
	ON_COMMAND( ID_ACTION_ROTATE, OnActionRotate )
	ON_UPDATE_COMMAND_UI( ID_ACTION_ROTATE, OnUpdateActionRotate )
	ON_COMMAND( ID_ACTION_SCALE, OnActionScale )
	ON_UPDATE_COMMAND_UI( ID_ACTION_SCALE, OnUpdateActionScale )
	ON_COMMAND( ID_ACTION_TRANSLATE, OnActionTranslate)
	ON_UPDATE_COMMAND_UI( ID_ACTION_TRANSLATE, OnUpdateActionTranslate )
	ON_COMMAND( ID_AXIS_X, OnAxisX)
	ON_UPDATE_COMMAND_UI( ID_AXIS_X, OnUpdateAxisX )
	ON_COMMAND( ID_AXIS_Y, OnAxisY )
	ON_UPDATE_COMMAND_UI( ID_AXIS_Y, OnUpdateAxisY )
	ON_COMMAND( ID_AXIS_Z, OnAxisZ )
	ON_UPDATE_COMMAND_UI( ID_AXIS_Z, OnUpdateAxisZ )
	ON_COMMAND( ID_LIGHT_SHADING_FLAT, OnLightShadingFlat )
	ON_UPDATE_COMMAND_UI( ID_LIGHT_SHADING_FLAT, OnUpdateLightShadingFlat )
	ON_COMMAND( ID_LIGHT_SHADING_GOURAUD, OnLightShadingGouraud )
	ON_UPDATE_COMMAND_UI( ID_LIGHT_SHADING_GOURAUD, OnUpdateLightShadingGouraud )
	ON_COMMAND( ID_LIGHT_CONSTANTS, OnLightConstants )
	//}}AFX_MSG_MAP
    ON_WM_LBUTTONDOWN( )
    ON_WM_MOUSEMOVE( )
    ON_COMMAND( ID_OPTIONS_MOUSE_SETTINGS, &COpenGLView::OnOptionsMouseSettings )
    ON_COMMAND( ID_OPTIONS_PERSPECTIVE_SETTINGS, &COpenGLView::OnOptionsPerspectiveSettings )
    ON_COMMAND( ID_VIEW_SHOW_VERTEX_NORMALS, &COpenGLView::OnViewShowVertexNormals )
    ON_UPDATE_COMMAND_UI( ID_VIEW_SHOW_VERTEX_NORMALS, &COpenGLView::OnUpdateViewShowVertexNormals )
    ON_COMMAND( ID_MODE_CAMERA, &COpenGLView::OnModeCamera )
    ON_UPDATE_COMMAND_UI( ID_MODE_CAMERA, &COpenGLView::OnUpdateModeCamera )
    ON_COMMAND( ID_MODE_OBJECT, &COpenGLView::OnModeObject )
    ON_UPDATE_COMMAND_UI( ID_MODE_OBJECT, &COpenGLView::OnUpdateModeObject )
    ON_COMMAND( ID_VIEW_SHOW_BOUNDING_BOX, &COpenGLView::OnViewShowBoundingBox )
    ON_UPDATE_COMMAND_UI( ID_VIEW_SHOW_BOUNDING_BOX, &COpenGLView::OnUpdateViewShowBoundingBox )
    ON_COMMAND( ID_VIEW_SHOW_FACE_NORMALS, &COpenGLView::OnViewShowFaceNormals )
    ON_UPDATE_COMMAND_UI( ID_VIEW_SHOW_FACE_NORMALS, &COpenGLView::OnUpdateViewShowFaceNormals )
    ON_COMMAND( ID_VIEW_RESET_VIEW, &COpenGLView::OnViewResetView )
    ON_COMMAND( ID_OPTIONS_COLOR_SETTINGS, &COpenGLView::OnOptionsColorSettings )
    ON_COMMAND( ID_AXIS_FREE_CONTROL, &COpenGLView::OnAxisFreeControl )
    ON_UPDATE_COMMAND_UI( ID_AXIS_FREE_CONTROL, &COpenGLView::OnUpdateAxisFreeControl )
END_MESSAGE_MAP( )


// A patch to fix GLaux disappearance from VS2005 to VS2008
void auxSolidCone( GLfloat radius, GLfloat height )
{
    GLUquadric *quad = gluNewQuadric( );
    gluQuadricDrawStyle( quad, GLU_FILL );
    gluCylinder( quad, radius, 0.0, height, 20, 20 );
    gluDeleteQuadric( quad );
}

void COpenGLView::resetView( )
{
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    Invalidate( );
}

/////////////////////////////////////////////////////////////////////////////
// COpenGLView construction/destruction

COpenGLView::COpenGLView( )                 // Set default values at startup
    : m_InitialMouseCoord( 0 )
    , m_LastMouseCoord( 0 )

    , m_fRotMouseSensitivity( 0.49f )       // the Factor multiplication is
    , m_fTraMouseSensitivity( 0.49f )       // done within the constructor's
    , m_fScaMouseSensitivity( 0.49f )       // body

    , m_fRotMouseSensitivityFactor( 1.0f )  // empirical values that equalize
    , m_fTraMouseSensitivityFactor( 0.009f )// the visual speed of these three
    , m_fScaMouseSensitivityFactor( 0.007f )// types of transformations

    , actionAxisBitVector( AXIS_X )            // axis X is activated
    , m_bShowVertexNormals( false )         // don't display
    , m_bShowFaceNormals( false )             
    , m_bShowBoundingBox( false )

    , m_nMode( MODE_OBJECT )                // operate with model (object)
{
	
    m_fRotMouseSensitivity *= m_fRotMouseSensitivityFactor;
    m_fTraMouseSensitivity *= m_fTraMouseSensitivityFactor;
    m_fScaMouseSensitivity *= m_fScaMouseSensitivityFactor;

	m_nAxis     = ID_AXIS_X;
    m_nPrevAxis = ID_AXIS_X;
	m_nAction   = ID_ACTION_ROTATE;
	m_nView     = ID_VIEW_ORTHOGRAPHIC_VIEW;	
	m_bIsPerspective = false;

	m_nLightShading = ID_LIGHT_SHADING_FLAT;

	m_lMaterialAmbient      = 0.2;
	m_lMaterialDiffuse      = 0.8;
	m_lMaterialSpecular     = 1.0;
	m_nMaterialCosineFactor = 32;

	//init the first light to be enabled
	m_lights[LIGHT_ID_1].enabled = true;


    // the next lines initialize the colors to their defaults using dialog
    // defaults
    CColorSettingsDialog dlg;
    dlg.restoreDefaults( );
    dlg.getColors( objectColor, backgroundColor, vertexNormalColor,
                   faceNormalColor, boundingBoxColor );

    overrideWireFrameColor = false;

	initializeTransformations( );
}


void COpenGLView::initializeTransformations( )
{
	m_transforms[ ID_ACTION_ROTATE] = new Rotation( );
    m_transforms[~ID_ACTION_ROTATE] = new FreeRotation( );
    m_transforms[ ID_ACTION_TRANSLATE] = new Translate( );
    m_transforms[~ID_ACTION_TRANSLATE] = new Translate( );
    m_transforms[ ID_ACTION_SCALE] = new Scale( );
    m_transforms[~ID_ACTION_SCALE] = new Scale( );
	updateSensitivity( m_fRotMouseSensitivity, m_fTraMouseSensitivity, m_fScaMouseSensitivity );
}

void COpenGLView::updateSensitivity( float rotate, float trans, float scale )
{
	m_transforms[ ID_ACTION_ROTATE]->updateSensitivity( rotate );
    m_transforms[~ID_ACTION_ROTATE]->updateSensitivity( rotate );
    m_transforms[ ID_ACTION_TRANSLATE]->updateSensitivity( trans );
    m_transforms[~ID_ACTION_TRANSLATE]->updateSensitivity( trans );
    m_transforms[ ID_ACTION_SCALE]->updateSensitivity( scale );
    m_transforms[~ID_ACTION_SCALE]->updateSensitivity( scale );
}


COpenGLView::~COpenGLView( )
{
	delete m_transforms[ ID_ACTION_ROTATE];
    delete m_transforms[~ID_ACTION_ROTATE];
    delete m_transforms[ ID_ACTION_TRANSLATE];
    delete m_transforms[~ID_ACTION_TRANSLATE];
    delete m_transforms[ ID_ACTION_SCALE];
    delete m_transforms[~ID_ACTION_SCALE];
}


/////////////////////////////////////////////////////////////////////////////
// COpenGLView diagnostics

#ifdef _DEBUG
void COpenGLView::AssertValid( ) const
{
	CView::AssertValid( );
}

void COpenGLView::Dump( CDumpContext& dc ) const
{
	CView::Dump( dc );
}

COpenGLDoc* COpenGLView::GetDocument( ) // non-debug version is inline
{
	ASSERT( m_pDocument->IsKindOf( RUNTIME_CLASS( COpenGLDoc ) ) );
	return (COpenGLDoc*)m_pDocument;
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// COpenGLView Window Creation - Linkage of windows to OpenGL

BOOL COpenGLView::PreCreateWindow( CREATESTRUCT& cs )
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	// An OpenGL window must be created with the following
	// flags and must NOT include CS_PARENTDC for the
	// class style.

	cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

	return CView::PreCreateWindow( cs );
}



int COpenGLView::OnCreate( LPCREATESTRUCT lpCreateStruct ) 
{
	if ( CView::OnCreate( lpCreateStruct ) == -1 )
    {
		return -1;
    }

	InitializeOpenGL( );

	return 0;
}


// This method initialized the OpenGL system.
BOOL COpenGLView::InitializeOpenGL( )
{
	m_pDC = new CClientDC( this );


	if ( NULL == m_pDC ) // failure to get DC
    {
		::AfxMessageBox( "Couldn't get a valid DC." );
		return FALSE;
	}

	if ( !SetupPixelFormat( ) )
    {
		::AfxMessageBox("SetupPixelFormat failed.\n");
		return FALSE;
	}

	if ( 0 == ( m_hRC = ::wglCreateContext( m_pDC->GetSafeHdc( ) ) ) )
    {
		::AfxMessageBox( "wglCreateContext failed." );
		return FALSE;
	}

	if ( FALSE == ::wglMakeCurrent( m_pDC->GetSafeHdc( ), m_hRC ) )
    {
		::AfxMessageBox( "wglMakeCurrent failed." );
		return FALSE;
	}

	// specify black as clear color
	::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
	// specify the back of the buffer as clear depth (0 closest, 1 farthest)
	::glClearDepth( 1.0f );
	// enable depth testing (Enable z buffer - hidden surface removal)
	::glEnable( GL_DEPTH_TEST );

	// set default background color
    ::glClearColor( backgroundColor.getR( ), backgroundColor.getG( ),
                    backgroundColor.getB( ), backgroundColor.getA( ) );

	return TRUE;
}


BOOL COpenGLView::SetupPixelFormat( PIXELFORMATDESCRIPTOR* pPFD )
{
	// default pixel format for a single-buffered,
	// OpenGL-supporting, hardware-accelerated, 
	// RGBA-mode format. Pass in a pointer to a different
	// pixel format if you want something else
	PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
		1,                              // version number
		PFD_DRAW_TO_WINDOW |            // support window
		PFD_SUPPORT_OPENGL |            // support OpenGL
		PFD_DOUBLEBUFFER,               // double buffered
		PFD_TYPE_RGBA,                  // RGBA type
		24,                             // 24-bit color depth
		0, 0, 0, 0, 0, 0,               // color bits ignored
		0,                              // no alpha buffer
		0,                              // shift bit ignored
		0,                              // no accumulation buffer
		0, 0, 0, 0,                     // accumulation bits ignored
		16,                             // 16-bit z-buffer
		0,                              // no stencil buffer
		0,                              // no auxiliary buffer
		PFD_MAIN_PLANE,                 // main layer
		0,                              // reserved
		0, 0, 0                         // layer masks ignored
	};

	int pixelformat;
	PIXELFORMATDESCRIPTOR* pPFDtoUse;

	// let the user override the default pixel format
	pPFDtoUse = (0 == pPFD) ? &pfd : pPFD; 

	if ( 0 == ( pixelformat = ::ChoosePixelFormat( m_pDC->GetSafeHdc( ), pPFDtoUse ) ) )
    {
		::AfxMessageBox( "ChoosePixelFormat failed." );
		return FALSE;
	}

	if ( FALSE == ::SetPixelFormat( m_pDC->GetSafeHdc( ), pixelformat, pPFDtoUse ) )
    {
		::AfxMessageBox( "SetPixelFormat failed." );
		return FALSE;
	}

	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// COpenGLView message handlers

void COpenGLView::OnSize( UINT nType, int cx, int cy )
{
	CView::OnSize( nType, cx, cy );

	if ( 0 >= cx || 0 >= cy )
    {
		return;
	}

	// save the width and height of the current window
	m_WindowWidth = cx;
	m_WindowHeight = cy;

	// compute the aspect ratio
	// this will keep all dimension scales equal
	m_AspectRatio = (GLdouble)m_WindowWidth / (GLdouble)m_WindowHeight;

	// Now, set up the viewing area-select the full client area
	::glViewport( 0, 0, m_WindowWidth, m_WindowHeight );

	if ( GL_NO_ERROR != ::glGetError( ) )
    {
		::AfxMessageBox( "Error while trying to set viewport." );
	}

	// select the projection matrix as the recipient of
	// matrix operations (there's three to choose from)
	::glMatrixMode( GL_PROJECTION );
	// initialize the projection matrix to a pristine state
//	::glLoadIdentity();

	// select the viewing volume. You do it after you
	// get the aspect ratio and set the viewport
    if ( m_bIsPerspective )
    {
        SetupViewingFrustum( );
    }
    else
    {
	    SetupViewingOrthoConstAspect( );
    }

	// now select the modelview matrix and clear it
	// this is the mode we do most of our calculations in
	// so we leave it as the default mode.
	::glMatrixMode( GL_MODELVIEW );
}


BOOL COpenGLView::SetupViewingFrustum(void)
{
    if ( GL_NO_ERROR != ::glGetError() )
    {
        ::AfxMessageBox("Error.");
        return FALSE;
    }

	// select a default perspective viewing volume
	::gluPerspective( 40.0f, m_AspectRatio, 0.1f, 20.0f );

	// NOTE: Other commands you could have here are
	// glFrustum, which gives you much more control over
	// the perspective view, or glOrtho which is used for
	// parallel projections. No matter what you use, check
	// the error status when you set the viewing frustum!

	if ( GL_NO_ERROR != ::glGetError() )
    {
		::AfxMessageBox("Error while trying to set viewing frustum.");
		return FALSE;
	}

	return TRUE;
}


// This viewing projection gives us a constant aspect ratio. This is done by
// increasing the corresponding size of the ortho cube.
BOOL COpenGLView::SetupViewingOrthoConstAspect(void)
{
	double windowSize = 4;	// the size of the window in GL coordinate system.


	if ( m_AspectRatio > 1 )  // x is bigger than y
    {
		// Maintain y size and increase x size (and z) accordingly
		// by MULTIPLYING by the aspect ration.
		::glOrtho(-windowSize*m_AspectRatio/2.0, windowSize*m_AspectRatio/2.0,
                  -windowSize/2.0, windowSize/2.0,
                  -windowSize*m_AspectRatio/2.0, windowSize*m_AspectRatio/2.0);
	} else {
		// Maintain x size and increase y size (and z) accordingly, 
		// by DIVIDING the aspect Ration (because it's smaller than 1).
		::glOrtho(-windowSize/2.0, windowSize/2.0,
                  -windowSize/m_AspectRatio/2.0, windowSize/m_AspectRatio/2.0,
                  -windowSize/m_AspectRatio/2.0, windowSize/m_AspectRatio/2.0);
	}

	if( GL_NO_ERROR != ::glGetError() )
    {
		::AfxMessageBox("Error while trying to set viewing frustum.");
		return FALSE;
	}

	return TRUE;
}



BOOL COpenGLView::OnEraseBkgnd(CDC* pDC) 
{
	// Windows will clear the window with the background color every time your
    // window is redrawn, and then OpenGL will clear the viewport with its own
    // background color.

	// return CView::OnEraseBkgnd(pDC);
	return true;
}



/////////////////////////////////////////////////////////////////////////////
// COpenGLView drawing
/////////////////////////////////////////////////////////////////////////////

void COpenGLView::OnDraw(CDC* pDC)
{
	COpenGLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// clear screen & zbuffer

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if(m_bIsPerspective)
    {
        SetupViewingFrustum();
        glTranslatef(0, 0, -5.5);
    } 
    else
    {
        SetupViewingOrthoConstAspect();        
    }

    glMatrixMode(GL_MODELVIEW);

	// draw the axes
//	glPushMatrix();
	drawAxes();
//	glPopMatrix();

    // draw the scene
	RenderScene();

    // force rendering
	glFlush();
	SwapBuffers( wglGetCurrentDC() );
}


/////////////////////////////////////////////////////////////////////////////
// COpenGLView OpenGL Finishing and clearing...

void COpenGLView::OnDestroy() 
{
	CView::OnDestroy();


	// this call makes the current RC not current
	if ( FALSE == ::wglMakeCurrent( 0, 0 ) )
    {
		::AfxMessageBox("wglMakeCurrent failed.");
	}

	// delete the RC
	if ( m_hRC && (FALSE == ::wglDeleteContext( m_hRC )) )
    {
		::AfxMessageBox("wglDeleteContext failed.");
	}

	// delete the DC
	if ( m_pDC )
    {
		delete m_pDC;
	}
}



/////////////////////////////////////////////////////////////////////////////
// User Defined Functions

/*
inline void drawArrow(GLdouble Ax, GLdouble Ay, GLdouble Az,
                      GLdouble Bx, GLdouble By, GLdouble Bz,
                      GLfloat   R, GLfloat   G, GLfloat   B)
{
    glColor3f(R, G, B);
    glBegin(GL_LINES);
    glVertex3d(Ax, Ay, Az);
    glVertex3d(Bx, By, Bz);
    glEnd();

    glPushMatrix();
    glTranslatef(Ax, Ay, Az);
    glRotatef(90.0, 0.0, 1.0, 0.0);
    auxSolidCone(0.05, 0.5);
    glPopMatrix();

}
*/

void COpenGLView::drawAxes( )
{
	glLineWidth( 2.0 );

	// draw axis X
	glColor3f( 1.0f, 0.0f, 0.0f );
	glBegin( GL_LINES );
	glVertex3f( -0.1f, 0.0f, 0.0f );
	glVertex3f(  1.0f, 0.0f, 0.0f );
	glEnd( );
	glPushMatrix( );
	glTranslatef( 1.0f, 0.0f, 0.0f );
	glRotatef( 90.0f, 0.0f, 1.0f, 0.0f );
	auxSolidCone( 0.05f, 0.5f );
	glPopMatrix( );

    // draw axis Y
	glColor3f( 0.0f, 1.0f, 0.0f );
	glBegin( GL_LINES );
	glVertex3f( 0.0f, -0.1f, 0.0f );
	glVertex3f( 0.0f,  1.0f, 0.0f );
	glEnd( );
	glPushMatrix();
	glTranslatef( 0.0f, 1.0f, 0.0f );
	glRotatef( -90.0f, 1.0f, 0.0f, 0.0f );
	auxSolidCone( 0.05f, 0.5f );
	glPopMatrix();

    // draw axis Z
	glColor3f( 0.0f, 0.0f, 1.0f );
	glBegin( GL_LINES );
	glVertex3f( 0.0f, 0.0f, -0.1f );
	glVertex3f( 0.0f, 0.0f,  1.0f );
	glEnd( );
	glPushMatrix( );
	glTranslatef( 0.0f, 0.0f, 1.0f );
	auxSolidCone( 0.05f, 0.5f );
	glPopMatrix( );

	// return default line width
    glLineWidth( 1 );
    
    // return default color
	glColor3f( objectColor.getR( ), objectColor.getG( ), objectColor.getB( ) );
}


void COpenGLView::RenderScene( )
{

#pragma message( "TODO: implement line type/width control.")
    glLineWidth( 1.0 );


    for ( std::vector<PolyObject>::iterator it =
              ObjectStorage::getInstance( ).getAllObjects( ).begin( );
          it != ObjectStorage::getInstance( ).getAllObjects( ).end( );
          ++it )
    {
        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
        it->draw( );

        if ( m_bShowVertexNormals )
        {
            glColor3f( vertexNormalColor.getR( ), vertexNormalColor.getG( ), vertexNormalColor.getB( ) );
            it->drawVertexNormals( );
            glColor3f( objectColor.getR( ), objectColor.getG( ), objectColor.getB( ) );
        }

        if ( m_bShowFaceNormals )
        {
            glColor3f( faceNormalColor.getR( ), faceNormalColor.getG( ), faceNormalColor.getB( ) );
            it->drawFaceNormals( );
            glColor3f( objectColor.getR( ), objectColor.getG( ), objectColor.getB( ) );
        }
    }

    if ( m_bShowBoundingBox )
    {
        glColor3f( boundingBoxColor.getR( ), boundingBoxColor.getG( ), boundingBoxColor.getB( ) );
        ObjectStorage::getInstance( ).drawBoundingBox( );
        glColor3f( objectColor.getR( ), objectColor.getG( ), objectColor.getB( ) );
    }

#ifdef _DEBUG
    GL_ASSERT("End of RenderScene( )");
#endif
}


void COpenGLView::OnFileLoad( )
{
	TCHAR szFilters[]=_T( "IRIT Data Files (*.itd)|*.itd|All Files (*.*)|*.*||" );

	CFileDialog dlg( TRUE, "itd", "*.itd", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
                     szFilters );

	if ( dlg.DoModal( ) == IDOK )
    {
		m_strItdFileName = dlg.GetPathName( );		// full path and filename
		PngWrapper p;


        ObjectStorage::getInstance( ).clear( );     // initialize the object storage

        CGSkelProcessIritDataFiles( m_strItdFileName, 1 );


		// open the file and read it
		// your code here...


        if ( overrideWireFrameColor )
        {
            ObjectStorage::getInstance( ).disableColor( );
        }
        else
        {
            ObjectStorage::getInstance( ).enableColor( );
        }

        resetView( );

// done by resetView():		Invalidate( );	// force a WM_PAINT for drawing
	} 
}




// VIEW HANDLERS ///////////////////////////////////////////

// Note: that all the following Message Handlers act in a similar way.
// Each control or command has two functions associated with it.

void COpenGLView::OnViewOrthographicView( ) 
{
	m_nView = ID_VIEW_ORTHOGRAPHIC_VIEW;
	m_bIsPerspective = false;
	Invalidate( );		// redraw using the new view
}


void COpenGLView::OnUpdateViewOrthographicView( CCmdUI* pCmdUI ) 
{
	pCmdUI->SetCheck( m_nView == ID_VIEW_ORTHOGRAPHIC_VIEW );
}


void COpenGLView::OnViewPerspectiveView( ) 
{
	m_nView = ID_VIEW_PERSPECTIVE_VIEW;
	m_bIsPerspective = true;
	Invalidate( );
}


void COpenGLView::OnUpdateViewPerspectiveView(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_nView == ID_VIEW_PERSPECTIVE_VIEW);
}




// ACTION HANDLERS ///////////////////////////////////////////

void COpenGLView::OnActionRotate()
{
	m_nAction = ID_ACTION_ROTATE;

    // no axes selected
    if ( FREE_CONTROL_IS_SELECTED( actionAxisBitVector ) )
    {
        return;
    }

    // if more than one axis is selected - leave only the last chosen one active
    // because rotation can't be done along two axes at the same time
    switch (m_nAxis)
    {
		case ID_AXIS_X:
			SELECT_AXIS_X_ONLY( actionAxisBitVector );
    		break;
		case ID_AXIS_Y:
            SELECT_AXIS_Y_ONLY( actionAxisBitVector );
			break;
		case ID_AXIS_Z:
            SELECT_AXIS_Z_ONLY( actionAxisBitVector );
			break;
        case ID_AXIS_FREE_CONTROL:
            // no need to do anything
            break;
        default:
            break;
    }
}


void COpenGLView::OnUpdateActionRotate( CCmdUI* pCmdUI ) 
{
	pCmdUI->SetCheck( m_nAction == ID_ACTION_ROTATE );
}


void COpenGLView::OnActionTranslate( )
{
	m_nAction = ID_ACTION_TRANSLATE;
}


void COpenGLView::OnUpdateActionTranslate( CCmdUI* pCmdUI ) 
{
	pCmdUI->SetCheck( m_nAction == ID_ACTION_TRANSLATE );
}


void COpenGLView::OnActionScale( )
{
	m_nAction = ID_ACTION_SCALE;
}


void COpenGLView::OnUpdateActionScale( CCmdUI* pCmdUI ) 
{
	pCmdUI->SetCheck( m_nAction == ID_ACTION_SCALE );
}




// AXIS HANDLERS ///////////////////////////////////////////

// COpenGLView::OnAxisX()
// Gets called when the X button is pressed or when the Axis->X menu is selected.
// The only thing we do here is set the ChildView member variable m_nAxis to the 
// selected axis.

// COpenGLView::OnUpdateAxisX()
// Gets called when windows has to repaint either the X button or the Axis pop
// up menu.
// The control is responsible for its redrawing.
// It sets itself disabled when the action is a Scale action.
// It sets itself Checked if the current axis is the X axis.
void COpenGLView::OnAxisX( )
{
    m_nPrevAxis = m_nAxis;
	m_nAxis = ID_AXIS_X;

    if ( m_nAction == ID_ACTION_ROTATE )
    {
        SELECT_AXIS_X_ONLY( actionAxisBitVector );
    }
    else
    {
        TOGGLE_AXIS_X( actionAxisBitVector );
    }
}


void COpenGLView::OnUpdateAxisX(CCmdUI* pCmdUI) 
{
    // this allows few axes to be selected at the same time
    // ... != 0 is used for robustness, SetCheck accepts only 0, 1 or 2
	pCmdUI->SetCheck( ACT_ALONG_X(actionAxisBitVector) != 0 );
} 


void COpenGLView::OnAxisY()
{
    m_nPrevAxis = m_nAxis;
    m_nAxis = ID_AXIS_Y;

    if(m_nAction == ID_ACTION_ROTATE)
    {
        SELECT_AXIS_Y_ONLY(actionAxisBitVector);
    }
    else
    {
        TOGGLE_AXIS_Y(actionAxisBitVector);
    }
}


void COpenGLView::OnUpdateAxisY(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck( ACT_ALONG_Y(actionAxisBitVector) != 0 );
}


void COpenGLView::OnAxisZ()
{
    m_nPrevAxis = m_nAxis;
    m_nAxis = ID_AXIS_Z;

    if(m_nAction == ID_ACTION_ROTATE)
    {
        SELECT_AXIS_Z_ONLY(actionAxisBitVector);
    }
    else
    {
        TOGGLE_AXIS_Z(actionAxisBitVector);
    }
}


void COpenGLView::OnUpdateAxisZ(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck( ACT_ALONG_Z(actionAxisBitVector) != 0 );
}





// OPTIONS HANDLERS ///////////////////////////////////////////




// LIGHT SHADING HANDLERS ///////////////////////////////////////////

void COpenGLView::OnLightShadingFlat( )
{
	m_nLightShading = ID_LIGHT_SHADING_FLAT;
}


void COpenGLView::OnUpdateLightShadingFlat( CCmdUI* pCmdUI )
{
	pCmdUI->SetCheck( m_nLightShading == ID_LIGHT_SHADING_FLAT );
}


void COpenGLView::OnLightShadingGouraud( )
{
	m_nLightShading = ID_LIGHT_SHADING_GOURAUD;
}


void COpenGLView::OnUpdateLightShadingGouraud( CCmdUI* pCmdUI ) 
{
	pCmdUI->SetCheck( m_nLightShading == ID_LIGHT_SHADING_GOURAUD );
}


// LIGHT SETUP HANDLER ///////////////////////////////////////////

void COpenGLView::OnLightConstants( )
{
	CLightDialog dlg;


	for ( int id=LIGHT_ID_1; id<MAX_LIGHT; id++ )
	{	    
	    dlg.SetDialogData( (LightID)id, m_lights[id] );
	}
	dlg.SetDialogData( LIGHT_ID_AMBIENT, m_ambientLight );

	if ( dlg.DoModal( ) == IDOK )
	{
	    for ( int id=LIGHT_ID_1; id<MAX_LIGHT; id++ )
	    {
		    m_lights[id] = dlg.GetDialogData( (LightID)id );
	    }
	    m_ambientLight = dlg.GetDialogData( LIGHT_ID_AMBIENT );
	}

	Invalidate();
}



// Mouse handlers //////////////////////////////////////////////////////////////

void COpenGLView::OnLButtonDown( UINT nFlags, CPoint point )
{
    m_InitialMouseCoord = m_LastMouseCoord = point;

    CView::OnLButtonDown( nFlags, point );
}


void COpenGLView::OnMouseMove( UINT nFlags, CPoint point )
{
    // if the left mouse button is not depressed - return
    if ( !( nFlags & MK_LBUTTON ) )
    {
        CView::OnMouseMove( nFlags, point );
        return;
    }


    CPoint  mousePositionDelta   = point - m_LastMouseCoord;
    GLfloat modelviewMatrix[4*4] = {0};

    // + mousePositionDelta.y was added to make use of mouse movement along y
    // axis, the relation can be changed later to a more intuitive one
    // GLfloat actionDelta = mousePositionDelta.x + mousePositionDelta.y;

    if ( m_nMode == MODE_CAMERA )
    {
        glGetFloatv( GL_MODELVIEW_MATRIX, modelviewMatrix );
        glLoadIdentity( );
    }

    if ( FREE_CONTROL_IS_SELECTED( actionAxisBitVector ) )
    {
        m_transforms[~m_nAction]->apply( actionAxisBitVector, (float)mousePositionDelta.x, (float)mousePositionDelta.y );
    } 
    else
    {
        m_transforms[m_nAction]->apply( actionAxisBitVector, (float)mousePositionDelta.x, (float)mousePositionDelta.y );
    }

    if ( m_nMode == MODE_CAMERA )
    {
        glMultMatrixf( modelviewMatrix );
    }

    Invalidate( );

    // update the last coordinate by the current value before exit
    m_LastMouseCoord = point;

    CView::OnMouseMove( nFlags, point );
}


void COpenGLView::OnOptionsMouseSettings( )
{
    CMouseSettingsDialog dlg;

    dlg.setMouseSensitivityFactors( m_fRotMouseSensitivityFactor,
                                    m_fTraMouseSensitivityFactor,
                                    m_fScaMouseSensitivityFactor );

    dlg.setMouseSensitivity( m_fRotMouseSensitivity,
                             m_fTraMouseSensitivity,
                             m_fScaMouseSensitivity );

    if( dlg.DoModal( ) == IDOK )
    {
        dlg.getMouseSensitivity( m_fRotMouseSensitivity,
                                 m_fTraMouseSensitivity,
                                 m_fScaMouseSensitivity );

		updateSensitivity( m_fRotMouseSensitivity,
                           m_fTraMouseSensitivity,
                           m_fScaMouseSensitivity );
    }
}


void COpenGLView::OnOptionsPerspectiveSettings()
{
}


void COpenGLView::OnViewShowVertexNormals( )
{
    m_bShowVertexNormals = !m_bShowVertexNormals;
    Invalidate( );
}


void COpenGLView::OnUpdateViewShowVertexNormals( CCmdUI *pCmdUI )
{
    pCmdUI->SetCheck( m_bShowVertexNormals );
}


void COpenGLView::OnViewShowFaceNormals( )
{
    m_bShowFaceNormals = !m_bShowFaceNormals;
    Invalidate( );
}


void COpenGLView::OnUpdateViewShowFaceNormals( CCmdUI *pCmdUI)
{
    pCmdUI->SetCheck( m_bShowFaceNormals);
}

void COpenGLView::OnViewShowBoundingBox( )
{
    m_bShowBoundingBox = !m_bShowBoundingBox; 
    Invalidate( );
}


void COpenGLView::OnUpdateViewShowBoundingBox( CCmdUI *pCmdUI )
{
    pCmdUI->SetCheck( m_bShowBoundingBox );
}


void COpenGLView::OnModeCamera( )
{
    m_nMode = MODE_CAMERA;
}


void COpenGLView::OnUpdateModeCamera( CCmdUI *pCmdUI )
{
    pCmdUI->SetCheck( m_nMode == MODE_CAMERA );
}


void COpenGLView::OnModeObject( )
{
    m_nMode = MODE_OBJECT;
}


void COpenGLView::OnUpdateModeObject( CCmdUI *pCmdUI )
{
    pCmdUI->SetCheck( m_nMode == MODE_OBJECT );
}


void COpenGLView::OnViewResetView( )
{
    resetView( );
}


void COpenGLView::OnOptionsColorSettings( )
{
    CColorSettingsDialog dlg;

    dlg.setColors( objectColor, backgroundColor, vertexNormalColor,
                   faceNormalColor, boundingBoxColor );
    dlg.setOverrideWireframeColor( overrideWireFrameColor );

    if ( dlg.DoModal( ) == IDOK )
    {
        dlg.getColors( objectColor, backgroundColor, vertexNormalColor,
                       faceNormalColor, boundingBoxColor );

        // set background color, it's changed only from here
        glClearColor( backgroundColor.getR( ), backgroundColor.getG( ),
                      backgroundColor.getB( ), backgroundColor.getA( ) );

        // the next line is supposed to have a single =, not ==, do not change!
        if ( overrideWireFrameColor = dlg.getOverrideWireframeColor( ) )
        {
            ObjectStorage::getInstance( ).disableColor( );
        }
        else
        {
            ObjectStorage::getInstance( ).enableColor( );
        }
        // ObjectStorage::getInstance( ).setObjectColor( );
        // ...
        // ObjectStorage::getInstance( ).setBBColor( );

        Invalidate( );
    }
}


void COpenGLView::OnAxisFreeControl( )
{
    TOGGLE_FREE_CONTROL( actionAxisBitVector );
}


void COpenGLView::OnUpdateAxisFreeControl( CCmdUI *pCmdUI )
{
    pCmdUI->SetCheck( FREE_CONTROL_IS_SELECTED( actionAxisBitVector ) );
}
